package org.idea.spring.look.up.factory;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * 层次性的依赖查找 {@link org.springframework.beans.factory.HierarchicalBeanFactory}
 *
 * @Author linhao
 * @Date created in 10:55 下午 2021/4/10
 */
public class SpringHierarchicalLookUpDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(SpringHierarchicalLookUpDemo.class);
        applicationContext.refresh();

        ParentIocContainer parentIocContainer = new ParentIocContainer();
        ApplicationContext parentApplicationContext = parentIocContainer.getAndStartApplicationContext();
        // ConfigurableListableBeanFactory -> ConfigurableBeanFactory -> HierarchicalBeanFactory
        ConfigurableListableBeanFactory configurableListableBeanFactory = applicationContext.getBeanFactory();
        System.out.println("此时的父类BeanFactory为：" + configurableListableBeanFactory.getParentBeanFactory());
        configurableListableBeanFactory.setParentBeanFactory(parentApplicationContext);
        System.out.println("此时的父类BeanFactory为：" + configurableListableBeanFactory.getParentBeanFactory());
        ParentIocContainer.ParentBean parentBean = (ParentIocContainer.ParentBean) configurableListableBeanFactory.getBean("parentBean");
        System.out.println(parentBean);
        isContainedBean(configurableListableBeanFactory, "parentBean");
        displayContainsBean(configurableListableBeanFactory, "parentBean");
    }


    /**
     * 这里是子类可以获取自己和父类层次内部的bean，如果是使用containsLocalBean方法的话就只能判断当前所在层次的容器上下文
     *
     * @param beanFactory
     * @param beanName
     */
    public static void isContainedBean(HierarchicalBeanFactory beanFactory, String beanName) {
        System.out.println("getBean is " + beanFactory.getBean(beanName));
        System.out.printf("contained is [%s] ,beanFactory is [%s],beanName is [%s]\n", beanFactory.containsLocalBean(beanName), beanFactory, beanName);
    }

    /**
     * 查找关于父类容器内部的bean
     *
     * @param beanFactory
     * @param beanName
     */
    private static void displayContainsBean(HierarchicalBeanFactory beanFactory, String beanName) {
        System.out.printf("contained is [%s] ,beanFactory is [%s],beanName is [%s]\n", isContainedBeanInHoldApplication(beanFactory, beanName), beanFactory, beanName);
    }

    /**
     * 使用递归判断 -- 自上到下判断父类容器是否含有bean
     *
     * @param hierarchicalBeanFactory
     * @param beanName
     * @return
     */
    public static boolean isContainedBeanInHoldApplication(HierarchicalBeanFactory hierarchicalBeanFactory, String beanName) {
        BeanFactory parentBeanFactory = hierarchicalBeanFactory.getParentBeanFactory();
        if (parentBeanFactory instanceof HierarchicalBeanFactory) {
            HierarchicalBeanFactory parentHierarchicalBeanFactory = HierarchicalBeanFactory.class.cast(parentBeanFactory);
            if (isContainedBeanInHoldApplication(parentHierarchicalBeanFactory, beanName)) {
                return true;
            }
        }
        return hierarchicalBeanFactory.containsBean(beanName);
    }
}
